<template>
  <div class="new-chat-warpper">
    <div
      class="chat-body-wrapper"
      ref="chatBodyRef">
      <div class="chat-body">
        <ChatMsgItem
          v-for="(msg, index) in allMsgs"
          :key="index"
          @askQuestion="askQuestion"
          :message="msg.content"
          :isUser="!msg?.dialogFlag"
          :imgSrc="msg?.picUrl"
          :isFailed="msg?.isFailed"
          :isTyping="msg?.isTyping" />
      </div>
    </div>
    <div class="input-wrapper">
      <div
        class="chat-input-panel"
        :class="{ 'input-wrapper-active': inputHighlightFlag }">
        <div class="tool-bar">
          <el-upload
            v-model:file-list="picFileList"
            ref="uploadRef"
            class="chat-pic-upload"
            list-type="picture"
            :limit="1"
            accept="image/jpeg,image/png,image/bmp,image/x-icon,image/jpg,image/webP"
            :on-preview="handlePreview"
            :auto-upload="false">
            <template #trigger>
              <div class="pic-icon">
                <img
                  :src="picIcon"
                  alt="" />
              </div>
              <div>图片</div>
            </template>
          </el-upload>
        </div>
        <div class="input-wrapper">
          <el-input
            :disabled="hasImg"
            v-model="msgValue"
            :autosize="{ minRows: 3, maxRows: 15 }"
            type="textarea"
            @focus="inputHighlightFlag = true"
            @blur="inputHighlightFlag = false"
            @keydown="handleKeydown"
            :placeholder="hasImg ? '图片理解暂不支持文字输入' : '请输入对话内容，Enter发送，Shift+Enter换行'" />
          <div class="btn">
            <el-button
              :loading="loading"
              @click="sendMsg"
              type="primary"
              round>
              <template #icon>
                <div class="promotion-icon">
                  <img
                    :src="promotionIcon"
                    alt="" />
                </div>
              </template>
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
  import { getCurrentInstance, ref, onMounted, nextTick, computed, watch, onBeforeUnmount } from 'vue'
  import SSEClient from '@/http/sseService'
  import picIcon from '@/assets/img/page/picIcon.png'
  import promotionIcon from '@/assets/img/page/promotionIcon.png'
  import ChatMsgItem from './chatMsgItem.vue'
  import { guid } from '@/utils/toolUtils'
  import tipMessage from '@/utils/tipMessage'

  const emit = defineEmits(['createNewChat'])
  const { proxy } = getCurrentInstance()
  const props = defineProps({
    chatRoleInfo: {
      type: Object,
      default: null
    },
    someHistoryInfo: {
      type: Object,
      default: null
    },
    newChatFlag: {
      type: Boolean,
      default: false
    }
  })
  const msgValue = ref('')
  const allMsgs = ref([])
  const chatBodyRef = ref(null)
  const inputHighlightFlag = ref(false)
  const loading = ref(false)
  const picFileList = ref([])
  const conversationId = ref('')
  const someHistoryPromptId = computed(() => props.someHistoryInfo?.promptId)
  const someHistoryConversationId = computed(() => props.someHistoryInfo?.conversationId || '')
  const SSEApi = ref(null)
  const hasImg = computed(() => {
    msgValue.value = ''
    return picFileList.value.length > 0
  })
  const uploadRef = ref(null)
  /* ========方法========= */
  const askQuestion = ques => {
    if (ques) {
      msgValue.value = ques
      sendMsg()
    }
  }
  const handleChatError = () => {
    loading.value = false
    if (allMsgs.value.at(-1)?.isNewMsg) {
      allMsgs.value.at(-1).content = '服务暂无响应,重连中...'
      allMsgs.value.at(-1).dialogFlag = 1
      allMsgs.value.at(-1).isTyping = false
      allMsgs.value.at(-1).isFailed = true
      allMsgs.value.at(-1).apiError = true
      allMsgs.value.at(-1).isNewMsg = false
    }
    nextTick(() => {
      scrollToBottom()
    })
  }
  const handleSendTextMessage = async msg => {
    try {
      allMsgs.value.push({ content: msg?.trim(), dialogFlag: 0, isTyping: false })
      let reqData = {
        conversationId: conversationId.value,
        promptId: props.chatRoleInfo?.pkId || someHistoryPromptId.value || '',
        question: msg?.trim(),
        historyId: someHistoryConversationId.value
      }
      await proxy.$http.postWithBody('dialog/question', reqData)
      onSSEMessage()
      nextTick(() => {
        scrollToBottom()
      })
    } catch (error) {
      console.log(error)
      handleChatError()
    }
  }
  const handleSendImgMessage = async () => {
    try {
      loading.value = true
      allMsgs.value.push({ content: '', dialogFlag: 0, picUrl: picFileList.value[0].url })
      const formData = new FormData()
      formData.append('conversationId', conversationId.value)
      formData.append('historyId', someHistoryConversationId.value)
      formData.append('promptId', props.chatRoleInfo?.pkId || someHistoryPromptId.value || '')
      formData.append('imageFile', picFileList.value[0].raw)
      await proxy.$http.postWithBody('dialog/imageComprehend', formData)
      onSSEMessage()
      nextTick(() => {
        scrollToBottom()
      })
      uploadRef.value.clearFiles()
    } catch (error) {
      console.log(error)
      handleChatError()
      uploadRef.value.clearFiles()
    }
  }
  const createChatSSE = () => {
    loading.value = false
    conversationId.value = guid()
    let url = `${import.meta.env.VITE_SSE_URL}?conversationId=${conversationId.value}&historyId=${someHistoryConversationId.value}`
    SSEApi.value = new SSEClient(url)
    SSEApi.value.start()
    SSEApi.value.on('open', e => {
      console.log('已建立SSE连接~')
    })
    SSEApi.value.on('error', e => {
      handleChatError()
      console.warn('SSE连接出错~')
    })
  }

  const onSSEMessage = () => {
    loading.value = true
    let currentSSEMsg = ''
    const newMessageRepliedByAI = ref({ content: '开始深入分析中···', dialogFlag: 1, isTyping: true, isFailed: false, apiError: false, isNewMsg: true })
    allMsgs.value.push(newMessageRepliedByAI.value)
    SSEApi.value.on('message', event => {
      newMessageRepliedByAI.value.content = ''
      let { data } = event
      if (data === 'DONE') {
        newMessageRepliedByAI.value.isTyping = false
        newMessageRepliedByAI.value.content = currentSSEMsg
        newMessageRepliedByAI.value.isNewMsg = false
        currentSSEMsg = ''
        loading.value = false
      } else if (data === 'INVOKE_ALGORITHM_FAIL') {
        newMessageRepliedByAI.value.isTyping = false
        newMessageRepliedByAI.value.isFailed = true
        newMessageRepliedByAI.value.content = ' 算法服务出错，请稍后再试'
        newMessageRepliedByAI.value.isNewMsg = false
        currentSSEMsg = ''
        loading.value = false
      } else {
        currentSSEMsg += data
        newMessageRepliedByAI.value.content = currentSSEMsg
      }
      nextTick(() => {
        scrollToBottom()
      })
    })
  }
  const scrollToBottom = () => {
    const container = chatBodyRef.value
    if (container) {
      container.scrollTop = container.scrollHeight
    }
  }

  const sendMsg = (data = undefined) => {
    if (loading.value) {
      return
    }
    if (hasImg.value) {
      handleSendImgMessage()
    } else {
      if (msgValue.value.trim() !== '') {
        handleSendTextMessage(msgValue.value || data)
        msgValue.value = ''
      }
    }
  }
  const handleKeydown = event => {
    if (event.key === 'Enter') {
      if (event.shiftKey) {
        event.preventDefault() // 阻止默认行为（避免在 Edge 浏览器中会触发两次 Enter）
        msgValue.value += '\n'
      } else {
        // Enter 键发送
        event.preventDefault() // 阻止默认行为
        sendMsg()
      }
    }
  }
  const getSomeDialogDetail = async () => {
    try {
      if (!someHistoryPromptId.value) {
        return
      }
      const res = await proxy.$http.getWithUrl('dialog/detail', { promptId: someHistoryPromptId.value, conversationId: someHistoryConversationId.value })
      allMsgs.value = handleAIMsg(res)
      nextTick(() => {
        scrollToBottom()
      })
    } catch (error) {
      console.log(error)
    }
  }
  const handleAIMsg = rawData => {
    let result = rawData.map(item => {
      try {
        item.content = JSON.parse(item.content)
      } catch (error) {
        // console.log(error)
      }
      return item
    })
    return result
  }
  const getPreamble = async () => {
    try {
      // loading.value = true
      // allMsgs.value.push({ content: '', dialogFlag: 1, isTyping: true })
      let reqData = {
        conversationId: conversationId.value,
        promptId: props.chatRoleInfo.pkId
      }
      const res = await proxy.$http.postWithBody('dialog/preamble', reqData)
      onSSEMessage()
      nextTick(() => {
        scrollToBottom()
      })
      // allMsgs.value[0].content = res
      // allMsgs.value[0].isTyping = false
      // loading.value = false
    } catch (error) {
      console.log(error)
      handleChatError()
      // allMsgs.value[0].content = '提示词获取失败'
      // allMsgs.value[0].isFailed = true
      // allMsgs.value[0].isTyping = false
    }
  }
  const handlePreview = () => {}
  const initChat = () => {
    msgValue.value = ''
    allMsgs.value = []
    inputHighlightFlag.value = false
    loading.value = false
    picFileList.value = []
    conversationId.value = ''
    SSEApi.value?.stop()
    createChatSSE()
  }
  watch(
    () => props.someHistoryInfo,
    (newVal, oldVal) => {
      if (newVal?.promptId) {
        console.log('历史对话', newVal.conversationId)
        SSEApi.value?.stop()
        conversationId.value = newVal.conversationId
        createChatSSE()
        getSomeDialogDetail().then(() => {})
      }
    },
    {
      immediate: true,
      deep: true
    }
  )
  watch(
    () => props.newChatFlag,
    (newVal, oldVal) => {
      if (newVal) {
        console.log('新对话')
        SSEApi.value?.stop()
        createChatSSE()
      }
    },
    {
      immediate: true
    }
  )
  onMounted(() => {
    if (props.chatRoleInfo?.pkId) {
      console.log('与角色对话')
      SSEApi.value?.stop()
      createChatSSE()
      getPreamble()
    }
  })
  onBeforeUnmount(() => {
    SSEApi.value?.stop()
  })
  defineExpose({ initChat })
</script>

<style scoped lang="scss">
  .new-chat-warpper {
    height: 100%;
    width: 100%;
    padding: pxTvh(32) 0;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    & > .chat-body-wrapper {
      display: flex;
      justify-content: center;
      width: 100%;
      overflow-y: scroll;
      margin-bottom: pxTvh(24);
      & > .chat-body {
        width: 60%;
        box-sizing: border-box;
      }
    }
    & > .input-wrapper {
      display: flex;
      justify-content: center;
      width: 100%;
      & > .chat-input-panel {
        width: 60%;
        position: relative;
        min-height: pxTvh(160);
        background: #152345;
        border-radius: 8px;
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        padding: pxTvh(16) pxTvw(16);
        border: 1px solid transparent;
        & > .tool-bar {
          display: flex;
          align-items: center;
          padding-bottom: pxTvh(12);
          border-bottom: 1px solid #525c76;
          margin-bottom: pxTvh(12);

          & > .chat-pic-upload {
            color: rgba(165, 193, 255, 1);
            :deep(.el-upload) {
              height: 100%;
            }
            .pic-icon {
              width: pxTvw(16);
              height: pxTvw(16);
              margin-right: pxTvw(8);
              & > img {
                width: 100%;
                height: 100%;
              }
            }
            :deep(.el-upload:focus) {
              border-color: transparent;
              color: rgba(165, 193, 255, 1);
            }
            :deep(.el-upload .el-icon) {
              height: pxTvh(20);
              display: flex;
              align-items: center;
              margin-right: pxTvw(8);
              svg {
                margin-top: pxTvh(2);
              }
            }
            :deep(.el-upload-list) {
              display: flex;
              margin: 0;
              .el-upload-list__item {
                background-color: transparent;
                margin: 0 pxTvw(8) 0 0;
                padding: pxTvw(5);
                .el-upload-list__item-thumbnail {
                  height: pxTvw(60);
                  width: pxTvw(60);
                  background-color: transparent;
                }
                .el-icon--close {
                  color: #ffffff;
                  z-index: 999;
                }
              }
              .el-upload-list__item-info {
                display: none;
              }
            }
          }
        }
        & > .input-wrapper {
          flex: 1;
          box-sizing: border-box;
          position: relative;
          padding-right: pxTvh(100);
          & > :deep(.el-textarea) {
            width: 100%;
            height: 100%;
          }
          :deep(.el-textarea__inner) {
            height: 100%;
            background-color: #152345;
            box-shadow: none;
            color: #ffffff;
            resize: none;
          }
          & > .btn {
            position: absolute;
            right: pxTvw(0);
            bottom: pxTvh(0);
            width: pxTvw(52);
            height: pxTvh(32);
            :deep(.el-button) {
              width: 100%;
              height: 100%;
              background: linear-gradient(164deg, #957bff 0%, #2275f0 100%);
              .el-icon {
                display: flex;
                align-items: center;
                justify-content: center;
                .promotion-icon {
                  width: pxTvw(14);
                  height: pxTvw(14);
                  & > img {
                    width: 100%;
                    height: 100%;
                  }
                }
              }
            }
          }
        }
      }
      & > .input-wrapper-active {
        border: 1px solid #377dff;
      }
    }
  }
</style>
